<template>
  <div class="ssh_container">
    <div class="ssh_header">
      <span>{{host_info}}</span>
    </div>
    <div class="ssh_terminal">
        <div id="xterm"></div>
    </div>
  </div>
</template>

<script>
import 'xterm/css/xterm.css'
import { Terminal } from 'xterm'
import { FitAddon } from 'xterm-addon-fit'
import { AttachAddon } from 'xterm-addon-attach'
import io from 'socket.io-client'

export default {
  name: 'Xterm',
  data() {
    return {
      id: '',
      server_info: {},
      websock: '',
      initTermFlag: false
    }
  },
  computed: {
    host_info() {
      if (this.server_info && this.server_info.name) {
        return this.server_info.name + '|' + this.server_info.user + '@' + this.server_info.host + ':' + this.server_info.port
      } else {
        return ''
      }
    }
  },
  mounted() {
    this.id = this.$route.query.id
    this.initWebSocket()
  },
  beforeDestroy() {
    this.websock.close()
    this.term.dispose()
  },
  methods: {
    initTerm() {
      if (this.initTermFlag){
        return
      }
      const term = new Terminal({
        fontSize: 14,
        cursorBlink: true
      });
      const fitAddon = new FitAddon();
      term.loadAddon(fitAddon);
      term.open(document.getElementById('xterm'));
      fitAddon.fit();
      term.focus();
 
      /*term.onKey(e => {
        console.log(e)
        const ev = e.domEvent
        const printable = !ev.altKey && !ev.altGraphKey && !ev.ctrlKey && !ev.metaKey
        if (ev.keyCode === 13) {
          term.prompt()
        } else if (ev.keyCode === 8) {
          // Do not delete the prompt
          if (term._core.buffer.x > 2) {
            term.write('\b \b')
          }
        } else if (printable) {
          term.write(e.key)
        }
      })*/

      term.onData((data) => {
        this.websock.emit('term', data)
      })
      term.onResize(({cols, rows}) => {
        this.websock.emit('resize', [cols, rows])
      })
      window.onresize = () => fitAddon.fit()
      this.term = term
      this.initTermFlag = true
    },
    initWebSocket() {
      // 创建websocket连接
      this.websock = io('/webterm', {
        path:'/socket.io', 
        transports: ['websocket'],
        autoConnect: false
      }) 
      // 系统事件处理
      this.websock.on('connect', this.onConnect)                     // 打开连接
      this.websock.on('reconnect', this.onReconnect)                 // 打开连接
      this.websock.on('disconnect', this.onDisconnect)               // 关闭连接
      this.websock.on('error', this.onError)                         // 连接异常
      this.websock.on('connect_timeout', this.onConnectTimeout)      // 连接异常 
      this.websock.on('connect_error', this.onConnectError)          // 连接异常
      this.websock.on('reconnect_error', this.onReconnectError)      // 连接异常
      this.websock.on('reconnect_failed', this.onReconnectFailed)    // 连接异常
      this.websock.on('ping', this.onPing)                           // Ping
      this.websock.on('pong', this.onPong)                           // Pong
      this.websock.on('term-connected', this.doTermConnectedMessage) // 终端连接成功消息
      this.websock.on('term', this.doTermMessage)                    // 终端处理消息
      this.websock.on('server-info', this.doServerInfoMessage)
      this.websock.on('close', this.doCloseMessage)
      // 打开websocket连接
      this.websock.open()
    },
    onConnect(data) {
      this.initTerm()
      this.term.write('\r\nWebsocket connection is succeed.\r\n')
      this.websock.emit('open', {id: this.id})
    },
    onReconnect(data) {
      this.term.write('\r\nWebsocket reconnecting...')
      this.onConnect()
    },
    onDisconnect(data) {
      this.term.write('\r\nWebsocket connection is closed.')
    },
    onConnectError(error) {
      this.term.write('\r\nWebsocket connection error!')
    },
    onError(error) {
      this.term.write('\r\nerror!')
    },
    onConnectTimeout(timeout) {
      this.term.write('\r\nWebsocket connection timeout!')
    },
    onReconnectError(error) {
      this.term.write('\r\nWebsocket reconnection error!')
    },
    onReconnectFailed(error) {
      this.term.write('\r\nWebsocket reconnection failed!')
    },
    onPing(data) {
    },
    onPong(data) {
    },
    doTermConnectedMessage(data) {
      this.term.write(data);
      this.websock.emit('resize', [this.term.cols, this.term.rows])
    },
    doTermMessage(data) {
      this.term.write(data);
    },
    doServerInfoMessage(data) {
      this.server_info = data.data
    },
    doCloseMessage(data) {
      if (data.event === 'console-close') {
        window.close()
      } else {
        setTimeout(() => this.term.write('\r\nConnection is closed.\r\n'), 200)
      }
    }
  }
}
</script>

<style scoped>
.ssh_container {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
.ssh_header {
  height: 46px;
  padding: 0 10px;
  justify-content: space-between;
  background-color: #e6f7ff;
}
.ssh_header span {
  color: rgba(0,0,0,.65);
  font-size: 14px;
  font-family: -apple-system,BlinkMacSystemFont,Segoe UI,PingFang SC,Hiragino Sans GB,Microsoft YaHei,Helvetica Neue,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol;
  line-height: 46px;
}
.ssh_terminal {
  height: calc(100vh - 46px);
  flex: 1 1;
  display: flex;
  background-color: #000;
  padding-left: 5px;
}
.ssh_terminal>div {
  flex: 1 1;
}
</style>